﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Windows.Data;
using Socium.Domain;
using Socium.Domain.Collections;
using Socium.Domain.Documents;
using Socium.Domain.Tests.Sociometric;
using Socium.Documents.Sociograms;
using Socium.Documents.Sociomatrices;
using Socium.Persons;
using Socium.Presentation;
using Socium.Testings;
using Socium.Tests.Procedures;

namespace Socium {
	/// <summary>
	/// The ViewModel for the application's main window.
	/// </summary>
	public class MainWindowFormViewModel : PageViewModel, IFormViewService, IPageViewService {
		#region Fields

		ReadOnlyCollection<CommandViewModel> _commands;
		ObservableCollection<PageViewModel> _workspaces;

		readonly Document _document;
		readonly Database _database;

		readonly EnvironmentService _dialog_environment_service;
		readonly EnvironmentService _page_environment_service;

		#endregion // Fields

		#region Constructor

		public MainWindowFormViewModel(string display_name) : base(display_name) {
			_dialog_environment_service = new EnvironmentService(new DialogFormViewService(), this);
			_page_environment_service = new EnvironmentService(this, this);

			var directory = AppDomain.CurrentDomain.BaseDirectory;
			var files = System.IO.Directory.GetFiles(directory, "*.socium");
            _document = Document.Load(files[0]);
			//_document = new Document(); //Document.Load(files[0]);

			_database = Database.Load(System.IO.Path.Combine(directory, "Socium.sdb"));
		}

		#endregion // Constructor

		#region Commands

		/// <summary>
		/// Returns a read-only list of commands 
		/// that the UI can display and execute.
		/// </summary>
		public ReadOnlyCollection<CommandViewModel> Commands {
			get {
				if (_commands == null) {
					var cmds = CreateCommands();
					_commands = new ReadOnlyCollection<CommandViewModel>(cmds);
				}
				return _commands;
			}
		}

		List<CommandViewModel> CreateCommands() {
			var result = new List<CommandViewModel>();

			result.Add(new CommandViewModel("Save database", new Command(SaveDatabase)));
			result.Add(new CommandViewModel("Procedures", new Command(ShowProcedures)));
			result.Add(new CommandViewModel("People", new Command(ShowPeople)));
			result.Add(new CommandViewModel("Testings", new Command(ShowTestings)));

			result.Add(new CommandViewModel("Testing", new Command(ShowTesting)));

			result.AddRange(
				_document.Sociograms.MapLazy(
					sociogram => new CommandViewModel(
						sociogram.ToString() + " (sociogram)", 
						new Command(() => ShowSociogram(sociogram))
					)
				)
			);

			result.AddRange(
				_document.Sociomatrices.MapLazy(
					sociomatrix => new CommandViewModel(
						sociomatrix.ToString() + " (sociomatrix)", 
						new Command(() => ShowSociomatrix(sociomatrix))
					)
				)
			);

			result.AddRange(
				_database.Procedures.MapLazy(
					p => new CommandViewModel(
						p.ToString() + " (procedure)", 
						new Command(() => ShowProcedue(p)))));

			result.AddRange(
				_database.Procedures.MapLazy(
					p => new CommandViewModel(
						p.ToString() + " (go!)", 
						new Command(() => ExecuteProcedure(p)))));

			return result;
		}

		void ShowTestings() {
			var view_model = new TestingsIndexViewModel("Testings", _database, _page_environment_service);
			ShowWorkspace(view_model);
		}

		#endregion // Commands

		#region Workspaces

		/// <summary>
		/// Returns the collection of available workspaces to display.
		/// A 'workspace' is a ViewModel that can request to be closed.
		/// </summary>
		public ObservableCollection<PageViewModel> Workspaces {
			get {
				if (_workspaces == null) {
					_workspaces = new ObservableCollection<PageViewModel>();
					_workspaces.CollectionChanged += OnWorkspacesChanged;
				}
				return _workspaces;
			}
		}

		void OnWorkspacesChanged(object sender, NotifyCollectionChangedEventArgs e) {
			if (e.NewItems != null && e.NewItems.Count != 0)
				foreach (PageViewModel workspace in e.NewItems) {
					workspace.RequestClose += OnWorkspaceRequestClose;
				}

			if (e.OldItems != null && e.OldItems.Count != 0) {
				foreach (PageViewModel workspace in e.OldItems) {
					workspace.RequestClose -= OnWorkspaceRequestClose;
				}
			}
		}

		void OnWorkspaceRequestClose(object sender, EventArgs e) {
			var workspace = (PageViewModel)sender;
			workspace.Dispose();
			Workspaces.Remove(workspace);
		}

		#endregion // Workspaces

		void ShowPeople() {
			var view_model = new PeopleViewModel("People", _database, _dialog_environment_service);
			ShowWorkspace(view_model);
		}

		void ShowWorkspace(PageViewModel view_model) {
			Workspaces.Add(view_model);
			SetActiveWorkspace(view_model);
		}

		void ShowTesting() {
			var testing = new Domain.Tests.Testings.Testing();
			testing.Tests.Add(_database.Tests.First());

			_database.Testings.Add(testing);

			var view_model = new TestingViewModel(testing, _database);
			ShowWorkspace(view_model);
		}

		void ShowSociogram(Sociogram sociogram) {
			ShowWorkspace(new SociogramViewModel(_document, sociogram));
		}

		void ShowSociomatrix(Sociomatrix sociomatrix) {
			ShowWorkspace(new SociomatrixViewModel(_document, sociomatrix));
		}

		void ShowProcedures() {
			var view_model = new ProceduresIndexViewModel("Procedures", _database.Procedures, this);
			ShowWorkspace(view_model);
		}

		void SaveDatabase() {
			var directory = AppDomain.CurrentDomain.BaseDirectory;
			var path = System.IO.Path.Combine(directory, "Socium.sdb");

			_database.Save(path);
		}

		void ShowProcedue(Procedure procedure) {
			ShowWorkspace(new ProcedureViewModel(procedure));
		}

		void ExecuteProcedure(Procedure procedure) {
			ShowWorkspace(new Testings.Sociometric.ProcedureViewModel(_database, procedure));
		}

		#region Private Helpers

		void SetActiveWorkspace(PageViewModel view_model) {
			Debug.Assert(Workspaces.Contains(view_model));

			var collection_view = CollectionViewSource.GetDefaultView(Workspaces);
			if (collection_view != null) {
				collection_view.MoveCurrentTo(view_model);
			}
		}

		#endregion // Private Helpers

		void IFormViewService.Show(IFormViewModel workspace) {
			ShowWorkspace((PageViewModel) workspace);
		}

		public void Show(PageViewModel view_model) {
			ShowWorkspace(view_model);
		}
	}
}